package cn.iocoder.yudao.module.system.util.baidu;

import com.baidubce.appbuilder.base.exception.AppBuilderServerException;
import com.baidubce.appbuilder.console.appbuilderclient.AppBuilderClient;
import com.baidubce.appbuilder.model.appbuilderclient.AppBuilderClientIterator;
import com.baidubce.appbuilder.model.appbuilderclient.AppBuilderClientResult;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Getter;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author zhaoying
 */
public class BaiduAiUtils {
    private static final Logger logger = LoggerFactory.getLogger(BaiduAiUtils.class);

    // OkHttp 客户端，用于 OpenAPI 调用
    public static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder()
            .readTimeout(300, TimeUnit.SECONDS)
            .build();

    // API 相关常量
    private static final String QIANFAN_API_BASE_URL = "https://qianfan.baidubce.com/v2/app";
    private static final String CONVERSATION_ENDPOINT = "/conversation";
    private static final String CONVERSATION_RUNS_ENDPOINT = "/conversation/runs";
    private static final String CHAT_ENDPOINT = "/chat";
    private static final okhttp3.MediaType JSON_MEDIA_TYPE = okhttp3.MediaType.parse("application/json");

    //37eae24f1bb44c4d974a77cd0cb06bf3
    public static final String APP_BUILDER_TOKEN = "bce-v3/ALTAK-CJ2wsTJjGxkv86YSKzmPm/36e80d188ea58c3ff4ce10f80b1a16ab8a013629";

    //专业版id 0607546c-a206-4930-bf1a-74635b9f9364
    private static final String P_APP_ID = "931334f7-967b-4af5-9ec5-29f4aabfbccc";
    //体验版id
    private static final String E_APP_ID = "ab83ec47-12c1-4755-ba0f-c9318f2c37aa";
    //极速作答版 返回json
    private static final String S_APP_ID = "b9b12f97-3fa1-417e-8743-6e63481d1c22";

    //专业的
    private static final String M_APP_ID = "ce0358c6-2034-40f2-b81a-c6786d696397";

    //非json版的基础问题
    private static final String N_APP_ID = "71e88323-9760-4f0f-aae9-4974088fa558";

    //高考100问
    private static final String Q_APP_ID = "309511c3-8cac-42b4-834a-5cbf93ba4e3b";

    //行业趋势问答
    private static final String T_APP_ID = "458bf7a9-e606-47db-a79e-efb7ea058bb1";

    //热门专业
    private static final String H_APP_ID = "8ace75ee-4b20-4069-92fc-22427996d398";

    //慎选专业
    private static final String C_APP_ID = "fdb9b417-ad44-4145-a025-2fbe36c31ee3";

    //数据查询助手
    private static final String D_APP_ID = "ee4ab7c0-d9a5-4097-85ee-e4c97a6d4a25";

    //gugu专业版
    private static final String G_APP_ID = "96363856-bc44-4d0f-99a6-c038156f2925";

    //专业版-学校报告
    private static final String S_APP_ID_2 = "8eaaf7b8-a0bb-4787-800b-43b724566ef0";

    //专业版-专业报告
    private static final String M_APP_ID_2 = "88233a9d-0771-4353-ab78-8678111a20fc";

    //专业版-专业就业报告
    private static final String J_APP_ID = "396e8f0b-8b09-4860-aee0-ccc77fc7343f";

    //按省份查看行业趋势
    private static final String T_APP_ID_2 = "5b61c88b-f821-4beb-a046-6ae51926c470";

    //热门专业学校推荐
    private static final String H_APP_ID_2 = "a8008615-b23d-47c4-b5e6-e6752db637f4";

    //热门专业就业前景
    private static final String H_APP_ID_3 = "b73ec42a-f1aa-4ef7-8164-ec79c5f5aaa2";

    //专业版-专业就业分析
    private static final String J_APP_ID_2 = "e16538f6-812e-4ccb-ad5f-efd23129b230";

    //专业版-专业特色
    private static final String M_APP_ID_3 = "b9e547fc-dd34-4cff-9c54-9877d3d78769";

    //专业版-学校简介
    private static final String S_APP_ID_3 = "7a67b6a8-4db3-4c22-b0fa-25dd376231f8";

    // 版本枚举
    @Getter
    public enum Version {
        PROFESSIONAL(P_APP_ID),
        EXPERIENCE(E_APP_ID),
        SPEED(S_APP_ID),
        MAJOR(M_APP_ID),
        NORMAL(N_APP_ID),
        GRE_100(Q_APP_ID),
        TREND(T_APP_ID),
        HOT(H_APP_ID),
        CHOICE(C_APP_ID),
        DATA(D_APP_ID),
        GUGU(G_APP_ID),
        SCHOOL(S_APP_ID_2),
        MAJOR_2(M_APP_ID_2),
        JOB(J_APP_ID),
        TREND_2(T_APP_ID_2),
        HOT_2(H_APP_ID_2),
        HOT_3(H_APP_ID_3),
        JOB_2(J_APP_ID_2),
        MAJOR_3(M_APP_ID_3),
        SCHOOL_2(S_APP_ID_3)
        ;

        private final String appId;

        Version(String appId) {
            this.appId = appId;
        }

    }


    public static String mdConvertTHtml(String content){
        Parser parser = Parser.builder().build();
        Node document = parser.parse(content);
        String html = HtmlRenderer.builder().build().render(document);
        System.out.println(html);
        return html;
    }

    /**
     * 处理学校信息并返回JSON格式的学校和专业数据
     * @param previousResponse 前一个问题的响应
     * @param version 使用的版本
     * @return JSON格式的学校和专业信息
     */
    public static CompletableFuture<String> processSchoolInfo(String previousResponse, Version version) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                String schoolQuery = "";
                String combinedQuery = previousResponse + "|" + schoolQuery;
                String response = processQueryOpenApi(version.getAppId(), combinedQuery, false);
                if (response == null || response.isEmpty()) {
                    logger.error("Failed to get response for school info query");
                    return null;
                }
                return cleanAndValidateJson(response);
            } catch (Exception e) {
                logger.error("Error processing school info", e);
                return null;
            }
        }, executorService);
    }

    /**
     * 处理学生信息并返回分析结果
     * @param studentInfo 学生信息
     * @param version 使用的版本
     * @return 分析结果
     */
    public static CompletableFuture<String> processStudentInfo(String studentInfo, Version version) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                String response = processQueryOpenApi(version.getAppId(), studentInfo, false);
                if (response == null || response.isEmpty()) {
                    logger.error("Failed to get response for student info query");
                    return null;
                }
                return response;
            } catch (Exception e) {
                logger.error("Error processing student info", e);
                return null;
            }
        }, executorService);
    }

    // 创建线程池 - 优化为IO密集型任务配置
    private static final ExecutorService executorService = Executors.newFixedThreadPool(
            Math.max(20, Runtime.getRuntime().availableProcessors() * 4), // 线程数设置为CPU核心数的4倍，最少20个线程
            new ThreadFactory() {
                private final AtomicInteger threadNumber = new AtomicInteger(1);
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r, "AIProcessor-" + threadNumber.getAndIncrement());
                    thread.setDaemon(true); // 设置为守护线程
                    return thread;
                }
            }
    );

    // 优雅关闭线程池的钩子
    static {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                    executorService.shutdownNow();
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
            }
        }));
    }


    /**
     * 使用 OpenAPI 进行聊天
     * 注意：此方法返回的是 String，而不是 AppBuilderClientIterator
     *
     * @param appId 应用 ID
     * @param q 查询内容
     * @param stream 是否使用流式响应
     * @return 响应内容
     * @throws IOException 如果 API 调用失败
     */
    public static String chat(String appId, String q, Boolean stream) throws IOException {
        return chat(appId, q, stream, null);
    }

    /**
     * 使用 OpenAPI 进行聊天，支持文件 ID
     * 注意：此方法返回的是 String，而不是 AppBuilderClientIterator
     *
     * @param appId 应用 ID
     * @param q 查询内容
     * @param stream 是否使用流式响应
     * @param fileIds 文件 ID 列表，可以为 null
     * @return 响应内容
     * @throws IOException 如果 API 调用失败
     */
    public static String chat(String appId, String q, Boolean stream, List<String> fileIds) throws IOException {
        System.out.println(q);
        try {
            // 创建新的对话 ID
            String conversationId = createConversationOpenApiV2(appId);

            // 发送消息并获取响应
            return sendMessageOpenApiV2(appId, conversationId, q, fileIds, stream != null && stream);
        } catch (Exception e) {
            logger.error("Error in chat", e);
            throw new IOException("Error in chat: " + e.getMessage(), e);
        }
    }
    /**
     * 兼容原有代码的 processQuery 方法
     * 注意：此方法仅作为兼容层，实际使用 processQueryOpenApi 方法
     *
     * @param client 已经初始化的 AppBuilderClient（在新的实现中不会使用此参数）
     * @param query 查询内容
     * @param stream 是否使用流式响应
     * @return 响应内容
     */
    public static String processQuery(AppBuilderClient client, String query, boolean stream) {
        // 使用 OpenAPI 实现替代 AppBuilderClient
        try {
            // 由于 AppBuilderClient 没有 getAppId 方法，我们需要使用反射获取 appId
            String appId = null;
            try {
                // 使用反射获取 appId 字段
                java.lang.reflect.Field field = client.getClass().getDeclaredField("appId");
                field.setAccessible(true);
                appId = (String) field.get(client);
            } catch (Exception ex) {
                // 如果反射失败，尝试使用默认的 GUGU 应用 ID
                logger.warn("Failed to get appId from AppBuilderClient using reflection, using default GUGU appId", ex);
                appId = G_APP_ID;
            }

            return processQueryOpenApi(appId, query, stream);
        } catch (Exception e) {
            logger.error("Error in processQuery using OpenAPI", e);
            return null;
        }
    }

    /**
     * 清理和验证JSON字符串
     * @param jsonStr 原始JSON字符串
     * @return 清理后的JSON字符串
     */
    public static String cleanAndValidateJson(String jsonStr) {
        if (jsonStr == null || jsonStr.isEmpty()) {
            return null;
        }

        try {
            // 1. 首先找到第一个完整的JSON结构
            int firstBrace = jsonStr.indexOf("{");
            if (firstBrace == -1) {
                return null;
            }

            // 计算大括号的配对
            int braceCount = 0;
            int startIndex = firstBrace;
            int endIndex = -1;

            for (int i = firstBrace; i < jsonStr.length(); i++) {
                char c = jsonStr.charAt(i);
                if (c == '{') {
                    braceCount++;
                } else if (c == '}') {
                    braceCount--;
                    if (braceCount == 0) {
                        endIndex = i + 1;
                        break;
                    }
                }
            }

            if (endIndex == -1 || braceCount != 0) {
                logger.error("Invalid JSON structure: Unmatched braces");
                return null;
            }

            // 2. 提取完整的JSON部分
            String extracted = jsonStr.substring(startIndex, endIndex);

            // 3. 清理其他标记
            String cleaned = extracted.replaceAll("```\\s*json\\s*", "") // 移除```json标记
                    .replaceAll("```", "")            // 移除剩余的```标记
                    .trim();                          // 移除首尾空白

            // 4. 验证JSON是否有效
            ObjectMapper mapper = new ObjectMapper();
            mapper.readTree(cleaned); // 尝试解析JSON，如果无效会抛出异常

            return cleaned;
        } catch (Exception e) {
            logger.error("JSON清理或验证失败", e);
            return null;
        }
    }

    /**
     * 获取专业的详细特色信息
     * @param schoolName 学校名称
     * @param majorName 专业名称
     * @param version 使用的版本
     * @return 专业的详细特色信息
     */
    public static String getMajorDetails(String schoolName, String majorName, Version version) {
        try {
            String majorFeatureQuery = String.format("详细介绍%s的%s", schoolName, majorName);

            String response = processQueryOpenApi(Version.MAJOR_2.getAppId(), majorFeatureQuery, false);
            if (response == null || response.isEmpty()) {
                logger.error("Failed to get details for major: {} at school: {}", majorName, schoolName);
                return null;
            }
            return response;
        } catch (Exception e) {
            logger.error("Error getting major details for: " + majorName + " at school: " + schoolName, e);
            return null;
        }
    }

    /**
     * 获取专业岗位的详细分析报告
     * @param schoolName 学校名称
     * @param majorName 专业名称
     * @param version 使用的版本
     * @return 专业的详细特色信息
     */
    public static String getSchoolMajorDetails(String schoolName, String majorName, Version version) {
        try {
            String majorFeatureQuery = String.format("详细介绍%s的%s", schoolName, majorName);

            String response = processQueryOpenApi(version.getAppId(), majorFeatureQuery, false);
            if (response == null || response.isEmpty()) {
                logger.error("Failed to get details for major: {} at school: {}", majorName, schoolName);
                return null;
            }
            return response;
        } catch (Exception e) {
            logger.error("Error getting major details for: " + majorName + " at school: " + schoolName, e);
            return null;
        }
    }

    /**
     * 获取学校的详细特色信息
     * @param schoolName 学校名称
     * @param version 使用的版本
     * @return 学校的详细特色信息
     */
    public static String getSchoolDetails(String schoolName, Version version) {
        try {
            String schoolFeatureQuery = String.format("%s", schoolName);

            String response = processQueryOpenApi(version.getAppId(), schoolFeatureQuery, false);
            if (response == null || response.isEmpty()) {
                logger.error("Failed to get details for school: " + schoolName);
                return null;
            }
            return response;
        } catch (Exception e) {
            logger.error("Error getting school details for: " + schoolName, e);
            return null;
        }
    }

    /**
     * 创建聊天对话
     * 注意：此方法返回的是 CompletableFuture<String>，而不是 CompletableFuture<AppBuilderClientIterator>
     * 如果需要兼容原有代码，请使用 createChatConversationOpenApi 方法
     *
     * @param appId 应用 ID
     * @param q 查询内容
     * @return 包含响应内容的 CompletableFuture
     */
    public static CompletableFuture<String> createChatConversation(String appId, String q) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return processQueryOpenApi(appId, q, false);
            } catch (Exception e) {
                logger.error("Error creating chat conversation", e);
                throw new CompletionException(e);
            }
        }, executorService);
    }

    /**
     * 使用 OpenAPI 创建新的对话 ID
     * 注意：此方法已经过时，请使用 createConversationOpenApiV2 方法
     *
     * @param appId 应用 ID
     * @return 对话 ID
     * @throws IOException 如果 API 调用失败
     * @deprecated 请使用 {@link #createConversationOpenApiV2(String)}
     */
    public static String createConversationOpenApi(String appId) throws IOException {
        try {
            // 构建请求体
            String requestBodyStr = String.format("{\"app_id\":\"%s\",\"messages\":[{\"role\":\"user\",\"content\":\"\u521b建新对话\"}]}", appId);
            RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, requestBodyStr);
            // 构建请求
            Request request = new Request.Builder()
                    .url(QIANFAN_API_BASE_URL + CONVERSATION_ENDPOINT)
                    .method("POST", body)
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Authorization", "Bearer " + APP_BUILDER_TOKEN)
                    .build();

            // 执行请求
            Response response = HTTP_CLIENT.newCall(request).execute();
            if (!response.isSuccessful()) {
                throw new IOException("创建对话失败: " + response.code() + " " + response.message());
            }

            // 解析响应
            String responseBody = response.body().string();
            ObjectMapper mapper = new ObjectMapper();
            JsonNode jsonNode = mapper.readTree(responseBody);

            // 提取对话 ID
            if (jsonNode.has("id")) {
                return jsonNode.get("id").asText();
            } else if (jsonNode.has("conversation_id")) {
                return jsonNode.get("conversation_id").asText();
            } else {
                throw new IOException("创建对话响应中未找到 id 或 conversation_id: " + responseBody);
            }
        } catch (Exception e) {
            logger.error("创建对话失败", e);
            throw new IOException("创建对话失败: " + e.getMessage(), e);
        }
    }

    /**
     * 使用 OpenAPI 创建新的对话 ID（新版本）
     *
     * @param appId 应用 ID
     * @return 对话 ID
     * @throws IOException 如果 API 调用失败
     */
    public static String createConversationOpenApiV2(String appId) throws IOException {
        try {
            // 使用 Jackson 构建 JSON 请求体
            ObjectMapper mapper = new ObjectMapper();
            ObjectNode requestBody = mapper.createObjectNode();
            requestBody.put("app_id", appId);

            ArrayNode messagesNode = requestBody.putArray("messages");
            ObjectNode messageNode = messagesNode.addObject();
            messageNode.put("role", "user");
            messageNode.put("content", "创建新对话");

            // 使用通用方法发送请求
            String responseBody = processApiRequest(QIANFAN_API_BASE_URL + CONVERSATION_ENDPOINT, requestBody);

            try {
                JsonNode jsonNode = mapper.readTree(responseBody);

                // 提取对话 ID
                if (jsonNode.has("id")) {
                    return jsonNode.get("id").asText();
                } else if (jsonNode.has("conversation_id")) {
                    return jsonNode.get("conversation_id").asText();
                } else {
                    // 检查是否有错误信息
                    if (jsonNode.has("code") && jsonNode.has("message")) {
                        String errorCode = jsonNode.get("code").asText();
                        String errorMessage = jsonNode.get("message").asText();
                        logger.error("API 返回错误: {} - {}", errorCode, errorMessage);
                        throw new IOException(String.format("API 错误: %s - %s", errorCode, errorMessage));
                    }

                    throw new IOException("创建对话响应中未找到 id 或 conversation_id: " + responseBody);
                }
            } catch (IOException e) {
                // 重新抛出 IOException
                throw e;
            } catch (Exception e) {
                logger.warn("响应体解析失败: " + responseBody, e);
                throw new IOException("响应体解析失败: " + e.getMessage(), e);
            }
        } catch (Exception e) {
            logger.error("创建对话失败", e);
            throw new IOException("创建对话失败: " + e.getMessage(), e);
        }
    }

    /**
     * 使用 OpenAPI 发送对话消息
     *
     * @param appId 应用 ID
     * @param conversationId 对话 ID
     * @param message 消息内容
     * @return 响应内容
     * @throws IOException 如果 API 调用失败
     */
    public static String sendMessageOpenApi(String appId, String conversationId, String message) throws IOException {
        return sendMessageOpenApi(appId, conversationId, message, null, true);
    }

    /**
     * 使用 OpenAPI 发送对话消息，支持文件 ID
     *
     * @param appId 应用 ID
     * @param conversationId 对话 ID
     * @param message 消息内容
     * @param fileIds 文件 ID 列表，可以为 null
     * @return 响应内容
     * @throws IOException 如果 API 调用失败
     */
    public static String sendMessageOpenApi(String appId, String conversationId, String message, List<String> fileIds) throws IOException {
        return sendMessageOpenApi(appId, conversationId, message, fileIds, true);
    }

    /**
     * 使用 OpenAPI 发送对话消息，支持文件 ID 和流式响应设置
     * 注意：此方法已经过时，请使用 sendMessageOpenApiV2 方法
     *
     * @param appId 应用 ID
     * @param conversationId 对话 ID
     * @param message 消息内容
     * @param fileIds 文件 ID 列表，可以为 null
     * @param stream 是否使用流式响应
     * @return 响应内容
     * @throws IOException 如果 API 调用失败
     * @deprecated 请使用 {@link #sendMessageOpenApiV2(String, String, String, List, boolean)}
     */
    public static String sendMessageOpenApi(String appId, String conversationId, String message, List<String> fileIds, boolean stream) throws IOException {
        try {
            // 使用 Jackson 构建 JSON 请求体，避免手动拼接字符串可能导致的转义问题
            ObjectMapper mapper = new ObjectMapper();
            ObjectNode requestBody = mapper.createObjectNode();
            requestBody.put("app_id", appId);
            requestBody.put("query", message);
            requestBody.put("stream", stream);
            requestBody.put("conversation_id", conversationId);

            // 添加文件 ID，如果有的话
            if (fileIds != null && !fileIds.isEmpty()) {
                ArrayNode fileIdsNode = requestBody.putArray("file_ids");
                for (String fileId : fileIds) {
                    fileIdsNode.add(fileId);
                }
            }

            String requestBodyStr = mapper.writeValueAsString(requestBody);
            logger.info("Request body: {}", requestBodyStr);
            RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, requestBodyStr);

            // 构建请求
            Request request = new Request.Builder()
                    .url(QIANFAN_API_BASE_URL + CONVERSATION_RUNS_ENDPOINT)
                    .method("POST", body)
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Authorization", "Bearer " + APP_BUILDER_TOKEN)
                    .build();

            // 执行请求
            logger.info("Sending request to: {}", QIANFAN_API_BASE_URL + CONVERSATION_RUNS_ENDPOINT);
            Response response = HTTP_CLIENT.newCall(request).execute();
            if (!response.isSuccessful()) {
                String errorBody = response.body() != null ? response.body().string() : "";
                logger.error("发送消息失败: {} {} \n请求体: {} \n响应体: {}",
                        response.code(), response.message(), requestBodyStr, errorBody);

                // 尝试解析错误信息
                try {
                    JsonNode errorNode = mapper.readTree(errorBody);
                    if (errorNode.has("code") && errorNode.has("message")) {
                        String errorCode = errorNode.get("code").asText();
                        String errorMessage = errorNode.get("message").asText();
                        throw new IOException(String.format("API 错误: %s - %s", errorCode, errorMessage));
                    }
                } catch (Exception e) {
                    // 如果解析错误信息失败，使用原始错误信息
                    logger.debug("解析错误信息失败", e);
                }

                throw new IOException("发送消息失败: " + response.code() + " " + response.message() + "\n请求体: " + requestBodyStr + "\n响应体: " + errorBody);
            }

            // 解析响应 - 只读取一次响应体
            String responseBody = response.body() != null ? response.body().string() : "";
            logger.info("收到响应: {}", responseBody.length() > 500 ? responseBody.substring(0, 500) + "..." : responseBody);

            // 检查是否是 SSE 格式的响应（以 "data:" 开头）
            if (responseBody.trim().startsWith("data:") || responseBody.contains("data: {")) {
                // 处理 SSE 格式的响应
                return parseSSEResponse(responseBody);
            } else {
                // 处理正常 JSON 响应
                try {
                    JsonNode jsonNode = mapper.readTree(responseBody);

                    // 提取回答内容
                    if (jsonNode.has("answer")) {
                        return jsonNode.get("answer").asText();
                    } else if (jsonNode.has("result")) {
                        return jsonNode.get("result").asText();
                    } else if (jsonNode.has("output") && jsonNode.get("output").has("text")) {
                        return jsonNode.get("output").get("text").asText();
                    } else {
                        // 检查是否有错误信息
                        if (jsonNode.has("code") && jsonNode.has("message")) {
                            String errorCode = jsonNode.get("code").asText();
                            String errorMessage = jsonNode.get("message").asText();
                            logger.error("API 返回错误: {} - {}", errorCode, errorMessage);
                            throw new IOException(String.format("API 错误: %s - %s", errorCode, errorMessage));
                        }

                        // 输出响应体便于调试
                        logger.warn("响应体内容: " + responseBody);
                        throw new IOException("发送消息响应中未找到 answer, result 或 output.text: " + responseBody);
                    }
                } catch (IOException e) {
                    // 重新抛出 IOException
                    throw e;
                } catch (Exception e) {
                    logger.warn("响应体解析失败: " + responseBody, e);
                    throw new IOException("响应体解析失败: " + e.getMessage(), e);
                }
            }
        } catch (Exception e) {
            logger.error("发送消息失败", e);
            throw new IOException("发送消息失败: " + e.getMessage(), e);
        }
    }

    /**
     * 使用 OpenAPI 发送对话消息，支持文件 ID 和流式响应设置（新版本）
     *
     * @param appId 应用 ID
     * @param conversationId 对话 ID
     * @param message 消息内容
     * @param fileIds 文件 ID 列表，可以为 null
     * @param stream 是否使用流式响应
     * @return 响应内容
     * @throws IOException 如果 API 调用失败
     */
    public static String sendMessageOpenApiV2(String appId, String conversationId, String message, List<String> fileIds, boolean stream) throws IOException {
        try {
            // 使用 Jackson 构建 JSON 请求体
            ObjectMapper mapper = new ObjectMapper();
            ObjectNode requestBody = mapper.createObjectNode();
            requestBody.put("app_id", appId);
            requestBody.put("query", message);
            requestBody.put("stream", stream);
            requestBody.put("conversation_id", conversationId);

            // 添加文件 ID，如果有的话
            if (fileIds != null && !fileIds.isEmpty()) {
                ArrayNode fileIdsNode = requestBody.putArray("file_ids");
                for (String fileId : fileIds) {
                    fileIdsNode.add(fileId);
                }
            }

            // 使用通用方法发送请求
            String responseBody = processApiRequest(QIANFAN_API_BASE_URL + CONVERSATION_RUNS_ENDPOINT, requestBody);

            // 检查是否是 SSE 格式的响应（以 "data:" 开头）
            if (responseBody.trim().startsWith("data:") || responseBody.contains("data: {")) {
                // 处理 SSE 格式的响应
                return parseSSEResponse(responseBody);
            } else {
                // 处理正常 JSON 响应
                try {
                    JsonNode jsonNode = mapper.readTree(responseBody);

                    // 提取回答内容
                    if (jsonNode.has("answer")) {
                        return jsonNode.get("answer").asText();
                    } else if (jsonNode.has("result")) {
                        return jsonNode.get("result").asText();
                    } else if (jsonNode.has("output") && jsonNode.get("output").has("text")) {
                        return jsonNode.get("output").get("text").asText();
                    } else {
                        // 检查是否有错误信息
                        if (jsonNode.has("code") && jsonNode.has("message")) {
                            String errorCode = jsonNode.get("code").asText();
                            String errorMessage = jsonNode.get("message").asText();
                            logger.error("API 返回错误: {} - {}", errorCode, errorMessage);
                            throw new IOException(String.format("API 错误: %s - %s", errorCode, errorMessage));
                        }

                        // 输出响应体便于调试
                        logger.warn("响应体内容: " + responseBody);
                        throw new IOException("发送消息响应中未找到 answer, result 或 output.text: " + responseBody);
                    }
                } catch (IOException e) {
                    // 重新抛出 IOException
                    throw e;
                } catch (Exception e) {
                    logger.warn("响应体解析失败: " + responseBody, e);
                    throw new IOException("响应体解析失败: " + e.getMessage(), e);
                }
            }
        } catch (Exception e) {
            logger.error("发送消息失败", e);
            throw new IOException("发送消息失败: " + e.getMessage(), e);
        }
    }

    /**
     * 解析 SSE 格式的响应
     *
     * @param sseResponse SSE 格式的响应字符串
     * @return 提取的回答内容
     * @throws IOException 如果解析失败
     */
    private static String parseSSEResponse(String sseResponse) throws IOException {
        StringBuilder fullAnswer = new StringBuilder();
        ObjectMapper mapper = new ObjectMapper();

        // 处理可能的特殊情况，如果响应以 "data:" 开头但不是有效的 JSON
        if (sseResponse.startsWith("data:") && !sseResponse.contains("{")) {
            logger.warn("响应以 data: 开头但不包含 JSON: " + sseResponse);
            return "[系统响应格式异常] 请重试或联系管理员";
        }

        // 处理错误信息中的特定情况
        if (sseResponse.contains("Unrecognized token 'data'")) {
            logger.warn("检测到 'Unrecognized token data' 错误: " + sseResponse);
            // 尝试提取有效的 JSON 部分
            int jsonStart = sseResponse.indexOf("{\"request_id\"");
            if (jsonStart >= 0) {
                try {
                    String jsonPart = sseResponse.substring(jsonStart);
                    int jsonEnd = jsonPart.indexOf("}")+1;
                    if (jsonEnd > 0) {
                        String validJson = jsonPart.substring(0, jsonEnd);
                        JsonNode node = mapper.readTree(validJson);
                        if (node.has("answer")) {
                            return node.get("answer").asText();
                        }
                    }
                } catch (Exception e) {
                    logger.debug("尝试提取 JSON 失败", e);
                }
            }
            return "[系统响应格式异常] 请重试或联系管理员";
        }

        // 分行处理 SSE 响应
        String[] lines = sseResponse.split("\n");
        for (String line : lines) {
            line = line.trim();
            if (line.startsWith("data:")) {
                // 去除 "data:" 前缀
                int jsonStart = line.indexOf("{");
                if (jsonStart < 0) {
                    continue; // 跳过不包含 JSON 对象的行
                }
                String jsonData = line.substring(jsonStart);
                try {
                    // 处理可能的 JSON 截断问题
                    if (!jsonData.endsWith("}")) {
                        int lastBrace = jsonData.lastIndexOf("}");
                        if (lastBrace > 0) {
                            jsonData = jsonData.substring(0, lastBrace + 1);
                        }
                    }

                    JsonNode jsonNode = mapper.readTree(jsonData);

                    // 提取回答内容
                    if (jsonNode.has("answer") && !jsonNode.get("answer").asText().isEmpty()) {
                        fullAnswer.append(jsonNode.get("answer").asText());
                    } else if (jsonNode.has("is_completion") && jsonNode.get("is_completion").asBoolean()) {
                        // 如果是最后一条消息，可能包含完整答案
                        if (jsonNode.has("content")) {
                            JsonNode contentNode = jsonNode.get("content");
                            if (contentNode.isArray() && contentNode.size() > 0) {
                                for (JsonNode item : contentNode) {
                                    if (item.has("outputs") && item.get("outputs").has("text")) {
                                        fullAnswer.append(item.get("outputs").get("text").asText());
                                    }
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    // 尝试处理可能的 JSON 格式问题
                    try {
                        // 如果有多个 JSON 对象连在一起，尝试只解析第一个
                        if (jsonData.contains("}{")) {
                            String firstJson = jsonData.substring(0, jsonData.indexOf("}{") + 1);
                            JsonNode jsonNode2 = mapper.readTree(firstJson);
                            if (jsonNode2.has("answer") && !jsonNode2.get("answer").asText().isEmpty()) {
                                fullAnswer.append(jsonNode2.get("answer").asText());
                            }
                        } else {
                            // 记录详细错误信息便于调试
                            logger.debug("SSE 行解析失败: " + line, e);
                        }
                    } catch (Exception e2) {
                        // 忽略解析错误，继续处理下一行
                        logger.debug("SSE 行解析失败（第二次尝试）: " + line, e2);
                    }
                }
            }
        }

        if (fullAnswer.length() == 0) {
            // 如果没有提取到答案，尝试从原始响应中提取文本
            try {
                // 尝试提取最后一个完整的 JSON 对象
                int lastDataIndex = sseResponse.lastIndexOf("data: {");
                if (lastDataIndex >= 0) {
                    String lastJson = sseResponse.substring(lastDataIndex + 6);
                    JsonNode lastNode = mapper.readTree(lastJson);
                    if (lastNode.has("answer") && !lastNode.get("answer").asText().isEmpty()) {
                        return lastNode.get("answer").asText();
                    }
                }

                logger.warn("SSE 响应中未找到答案: " + sseResponse);
            } catch (Exception e) {
                logger.warn("SSE 响应最终解析失败: " + sseResponse, e);
            }
            return "[系统响应解析失败] 请重试或联系管理员";
        }

        return fullAnswer.toString();
    }

    /**
     * 使用 OpenAPI 处理查询，支持文件 ID
     *
     * @param appId 应用 ID
     * @param query 查询内容
     * @param fileIds 文件 ID 列表，可以为 null
     * @return 响应内容
     */
    public static String processQueryOpenApi(String appId, String query, List<String> fileIds) {
        return processQueryOpenApi(appId, query, fileIds, true);
    }

    /**
     * 处理 API 请求的通用方法
     *
     * @param url API 端点 URL
     * @param requestBody 请求体 JSON 对象
     * @return 响应内容
     * @throws IOException 如果 API 调用失败
     */
    private static String processApiRequest(String url, ObjectNode requestBody) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        String requestBodyStr = mapper.writeValueAsString(requestBody);
        logger.info("Sending request to {}: {}", url, requestBodyStr);

        RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, requestBodyStr);
        Request request = new Request.Builder()
                .url(url)
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Authorization", "Bearer " + APP_BUILDER_TOKEN)
                .build();

        Response response = HTTP_CLIENT.newCall(request).execute();
        if (!response.isSuccessful()) {
            String errorBody = response.body() != null ? response.body().string() : "";
            logger.error("API 请求失败: {} {} \n请求体: {} \n响应体: {}",
                    response.code(), response.message(), requestBodyStr, errorBody);

            // 尝试解析错误信息
            try {
                JsonNode errorNode = mapper.readTree(errorBody);
                if (errorNode.has("code") && errorNode.has("message")) {
                    String errorCode = errorNode.get("code").asText();
                    String errorMessage = errorNode.get("message").asText();
                    throw new IOException(String.format("API 错误: %s - %s", errorCode, errorMessage));
                }
            } catch (Exception e) {
                // 如果解析错误信息失败，使用原始错误信息
                logger.debug("解析错误信息失败", e);
            }

            throw new IOException("请求失败: " + response.code() + " " + response.message() + "\n请求体: " + requestBodyStr + "\n响应体: " + errorBody);
        }

        String responseBody = response.body() != null ? response.body().string() : "";
        logger.info("收到响应: {}", responseBody.length() > 500 ? responseBody.substring(0, 500) + "..." : responseBody);
        return responseBody;
    }

    /**
     * 使用 OpenAPI 处理查询，支持文件 ID 和流式响应设置
     *
     * @param appId 应用 ID
     * @param query 查询内容
     * @param fileIds 文件 ID 列表，可以为 null
     * @param stream 是否使用流式响应
     * @return 响应内容
     */
    public static String processQueryOpenApi(String appId, String query, List<String> fileIds, boolean stream) {
        int maxRetries = 3; // 减少重试次数从10次到3次
        int retryCount = 0;
        long startTime = System.currentTimeMillis();

        while (retryCount < maxRetries) {
            String conversationId = null;
            try {
                // 创建新的会话
                conversationId = createConversationOpenApiV2(appId);
                logger.info("Created new conversation with ID: {} for attempt {}", conversationId, retryCount + 1);
                logger.debug("Query: {}", query.length() > 200 ? query.substring(0, 200) + "..." : query);

                // 发送消息
                String response = sendMessageOpenApiV2(appId, conversationId, query, fileIds, stream);

                if (response != null && !response.isEmpty()) {
                    long duration = System.currentTimeMillis() - startTime;
                    logger.info("Successfully got response on attempt {} in {}ms", retryCount + 1, duration);
                    return response;
                }

                logger.warn("Attempt {} failed with empty response", retryCount + 1);
                retryCount++;

                if (retryCount < maxRetries) {
                    long waitTime = Math.min(2000L, 500L * retryCount); // 减少等待时间，最大2秒
                    logger.info("Waiting {} ms before retry", waitTime);
                    Thread.sleep(waitTime);
                }
            } catch (Exception e) {
                logger.error("Error in processQueryOpenApi on attempt " + (retryCount + 1), e);
                retryCount++;

                if (retryCount < maxRetries) {
                    long waitTime = Math.min(2000L, 500L * retryCount); // 减少等待时间，最大2秒
                    logger.info("Waiting {} ms before retry after error: {}", waitTime, e.getMessage());
                    try {
                        Thread.sleep(waitTime);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException("Thread interrupted", ie);
                    }
                }
            }
        }

        long totalDuration = System.currentTimeMillis() - startTime;
        logger.error("Failed to get response after {} attempts in {}ms", maxRetries, totalDuration);
        return null;
    }

    /**
     * 使用 OpenAPI 处理查询，替代 AppBuilderClient 的 processQuery 方法
     *
     * @param appId 应用 ID
     * @param query 查询内容
     * @param stream 是否使用流式响应
     * @return 响应内容
     */
    public static String processQueryOpenApi(String appId, String query, boolean stream) {
        return processQueryOpenApi(appId, query, null, stream);
    }

    /**
     * 使用 OpenAPI 创建聊天对话，替代 AppBuilderClient 的 createChatConversation 方法
     * 注意：此方法返回的是 CompletableFuture<String>，而不是 CompletableFuture<AppBuilderClientIterator>
     *
     * @param appId 应用 ID
     * @param q 查询内容
     * @return 包含响应内容的 CompletableFuture
     */
    public static CompletableFuture<String> createChatConversationOpenApi(String appId, String q) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return processQueryOpenApi(appId, q, false);
            } catch (Exception e) {
                logger.error("Error creating chat conversation using OpenAPI", e);
                throw new CompletionException(e);
            }
        }, executorService);
    }

    /**
     * 使用 OpenAPI 处理学生信息，替代 processStudentInfo 方法
     *
     * @param studentInfo 学生信息
     * @param version 使用的版本
     * @return 分析结果
     */
    public static CompletableFuture<String> processStudentInfoOpenApi(String studentInfo, Version version) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                String response = processQueryOpenApi(version.getAppId(), studentInfo, false);
                if (response == null || response.isEmpty()) {
                    logger.error("Failed to get response for student info query using OpenAPI");
                    return null;
                }
                return response;
            } catch (Exception e) {
                logger.error("Error processing student info using OpenAPI", e);
                return null;
            }
        }, executorService);
    }

    /**
     * 使用 OpenAPI 处理学校信息，替代 processSchoolInfo 方法
     *
     * @param previousResponse 前一个问题的响应
     * @param version 使用的版本
     * @return JSON格式的学校和专业信息
     */
    public static CompletableFuture<String> processSchoolInfoOpenApi(String previousResponse, Version version) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                String schoolQuery = "请分析以下内容，提取所有学校及其推荐专业信息，以JSON格式输出。格式要求：" +
                        "{'\u5b66\u6821\u5217\u8868': [{'\u5b66\u6821\u540d\u79f0': '\u5b66\u6821\u540d', '\u7b80\u4ecb': '\u5b66\u6821\u7b80\u4ecb', '\u63a8\u8350\u4e13\u4e1a': [{'\u4e13\u4e1a\u540d\u79f0': '\u4e13\u4e1a\u540d', '\u7b80\u4ecb': '\u4e13\u4e1a\u7b80\u4ecb'}]}]}\u3002" +
                        "只输出JSON，不要其他任何内容。输出的JSON必须符合标准格式，不要添加额外的文本说明。";
                String combinedQuery = previousResponse + "|" + schoolQuery;

                String response = processQueryOpenApi(version.getAppId(), combinedQuery, false);
                if (response == null || response.isEmpty()) {
                    logger.error("Failed to get response for school info query using OpenAPI");
                    return null;
                }
                return cleanAndValidateJson(response);
            } catch (Exception e) {
                logger.error("Error processing school info using OpenAPI", e);
                return null;
            }
        }, executorService);
    }

    /**
     * 使用 OpenAPI 获取专业的详细特色信息，替代 getMajorDetails 方法
     *
     * @param schoolName 学校名称
     * @param majorName 专业名称
     * @param version 使用的版本
     * @return 专业的详细特色信息
     */
    public static String getMajorDetailsOpenApi(String schoolName, String majorName, Version version) {
        try {
            String majorFeatureQuery = String.format("详细介绍%s的%s", schoolName, majorName);
            String response = processQueryOpenApi(Version.MAJOR_2.getAppId(), majorFeatureQuery, false);

            if (response == null || response.isEmpty()) {
                logger.error("Failed to get details for major: {} at school: {} using OpenAPI", majorName, schoolName);
                return null;
            }
            return response;
        } catch (Exception e) {
            logger.error("Error getting major details for: " + majorName + " at school: " + schoolName + " using OpenAPI", e);
            return null;
        }
    }

    /**
     * 示例方法：如何使用 OpenAPI 调用方式
     * 此方法仅作为示例，展示如何使用 OpenAPI 创建对话并发送消息
     */
    public static void openApiExample() {
        try {
            // 使用 GUGU 专业版应用 ID
            String appId = G_APP_ID;

            // 1. 创建新的对话 ID
            String conversationId = createConversationOpenApi(appId);
            System.out.println("创建对话成功，对话 ID: " + conversationId);

            // 2. 发送消息并获取响应（使用流式响应）
            String message = "使用中文与我对话";
            String response = sendMessageOpenApi(appId, conversationId, message, null, true);
            System.out.println("发送消息成功（流式响应），响应: " + response);

            // 2.1 发送消息并获取响应（不使用流式响应）
            String message2 = "使用中文与我对话，不使用流式响应";
            String response2 = sendMessageOpenApi(appId, conversationId, message2, null, false);
            System.out.println("发送消息成功（非流式响应），响应: " + response2);

            // 3. 另一种方式：直接使用 processQueryOpenApi 方法（不使用流式响应）
            String query = "请介绍一下北京大学的计算机科学与技术专业";
            String result = processQueryOpenApi(appId, query, false);
            System.out.println("查询结果（非流式响应）: " + result);

            // 3.1 另一种方式：直接使用 processQueryOpenApi 方法（使用流式响应）
            String query2 = "请介绍一下清华大学的计算机科学与技术专业";
            String result2 = processQueryOpenApi(appId, query2, true);
            System.out.println("查询结果（流式响应）: " + result2);

            // 4. 使用异步方式调用
            CompletableFuture<String> future = createChatConversation(appId, "请介绍一下清华大学");
            future.thenAccept(r -> System.out.println("异步查询结果: " + r));

            // 5. 测试兼容原有方法
            String schoolInfo = processStudentInfo("我想了解北京大学", Version.GUGU).get();
            System.out.println("学生信息处理结果: " + schoolInfo);

            String majorDetails = getMajorDetails("北京大学", "计算机科学与技术", Version.MAJOR_2);
            System.out.println("专业详情: " + majorDetails);

            // 6. 测试原有 chat 方法
            String chatResult = chat(appId, "介绍一下上海交通大学", false);
            System.out.println("聊天结果: " + chatResult);

            // 7. 测试带文件 ID 的请求（使用流式响应）
            List<String> fileIds = new ArrayList<>();
            fileIds.add("cdd1e194-cfb7-4173-a154-795fae8535d9"); // 示例文件 ID
            String fileQueryResult = processQueryOpenApi(appId, "根据文件中的数据，统计这几所学校小学生有多少", fileIds, true);
            System.out.println("带文件的查询结果（流式响应）: " + fileQueryResult);

            // 7.1 测试带文件 ID 的请求（不使用流式响应）
            String fileQueryResult2 = processQueryOpenApi(appId, "根据文件中的数据，统计这几所学校小学生有多少", fileIds, false);
            System.out.println("带文件的查询结果（非流式响应）: " + fileQueryResult2);

            // 8. 测试带文件 ID 的聊天（使用流式响应）
            String chatWithFileResult = chat(appId, "分析文件中的学生成绩数据", true, fileIds);
            System.out.println("带文件的聊天结果（流式响应）: " + chatWithFileResult);

            // 8.1 测试带文件 ID 的聊天（不使用流式响应）
            String chatWithFileResult2 = chat(appId, "分析文件中的学生成绩数据", false, fileIds);
            System.out.println("带文件的聊天结果（非流式响应）: " + chatWithFileResult2);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 主方法，用于测试 OpenAPI 调用方式
     */
    public static void main(String[] args) {
        openApiExample();
    }

    /**
     * 创建对话，兼容测试方法
     *
     * @param appId 应用 ID
     * @param useOpenApi 是否使用 OpenAPI
     * @return 对话 ID
     * @throws IOException 如果 API 调用失败
     */
    public static String createConversation(String appId, boolean useOpenApi) throws IOException {
        return createConversationOpenApi(appId);
    }

    /**
     * 运行对话，兼容测试方法
     *
     * @param appId 应用 ID
     * @param query 查询内容
     * @param conversationId 对话 ID
     * @param useOpenApi 是否使用 OpenAPI
     * @return 响应内容
     * @throws IOException 如果 API 调用失败
     */
    public static String runConversation(String appId, String query, String conversationId, boolean useOpenApi) throws IOException {
        return sendMessageOpenApiV2(appId, conversationId, query, null, true);
    }

    /**
     * 运行对话，兼容测试方法，支持流式响应设置
     *
     * @param appId 应用 ID
     * @param query 查询内容
     * @param conversationId 对话 ID
     * @param useOpenApi 是否使用 OpenAPI
     * @param stream 是否使用流式响应
     * @return 响应内容
     * @throws IOException 如果 API 调用失败
     */
    public static String runConversation(String appId, String query, String conversationId, boolean useOpenApi, boolean stream) throws IOException {
        return sendMessageOpenApiV2(appId, conversationId, query, null, stream);
    }

    /**
     * 聊天，兼容测试方法
     *
     * @param appId 应用 ID
     * @param query 查询内容
     * @param stream 是否使用流式响应
     * @param useOpenApi 是否使用 OpenAPI
     * @return 响应内容或迭代器
     * @throws Exception 如果 API 调用失败
     */
    public static Object chatWithOptions(String appId, String query, boolean stream, boolean useOpenApi) throws Exception {
        return chat(appId, query, stream, null);
    }

    /**
     * 聊天，兼容测试方法，支持文件 ID
     *
     * @param appId 应用 ID
     * @param query 查询内容
     * @param stream 是否使用流式响应
     * @param useOpenApi 是否使用 OpenAPI
     * @param fileIds 文件 ID 列表
     * @return 响应内容或迭代器
     * @throws Exception 如果 API 调用失败
     */
    public static Object chatWithOptions(String appId, String query, boolean stream, boolean useOpenApi, List<String> fileIds) throws Exception {
        return chat(appId, query, stream, fileIds);
    }

    /**
     * 处理查询，兼容测试方法
     *
     * @param appId 应用 ID
     * @param query 查询内容
     * @param stream 是否使用流式响应
     * @param useOpenApi 是否使用 OpenAPI
     * @return 响应内容
     */
    public static String processQueryWithOptions(String appId, String query, boolean stream, boolean useOpenApi) {
        return processQueryOpenApi(appId, query, null, stream);
    }

    /**
     * 处理查询，兼容测试方法，支持文件 ID
     *
     * @param appId 应用 ID
     * @param query 查询内容
     * @param stream 是否使用流式响应
     * @param useOpenApi 是否使用 OpenAPI
     * @param fileIds 文件 ID 列表
     * @return 响应内容
     */
    public static String processQueryWithOptions(String appId, String query, boolean stream, boolean useOpenApi, List<String> fileIds) {
        return processQueryOpenApi(appId, query, fileIds, stream);
    }

    /**
     * 获取学校详情，兼容测试方法
     *
     * @param schoolName 学校名称
     * @param version 使用的版本
     * @param useOpenApi 是否使用 OpenAPI
     * @return 学校的详细特色信息
     */
    public static String getSchoolDetails(String schoolName, Version version, boolean useOpenApi) {
        return getSchoolDetails(schoolName, version);
    }
}
